#!/usr/bin/env python2
#-*- coding: utf-8 -*-

import sys
import time
import hashlib
import sqlalchemy
import traceback
import datetime
import web
import json
from Ump.objs.db import  models
from sqlalchemy.exc import ResourceClosedError
from sqlalchemy.orm.exc import NoResultFound

reload(sys)
sys.setdefaultencoding('utf-8')

cluster_table = 'cluster'
pool_table = 'pool'
volume_table = 'volume'
host_table = 'host'
disk_table = 'disk'
user_table = 'user'
iops_table = 'iops'
oplog_table = 'oplog'
alert_table = 'alert'
user_role_table = 'user_role'
role_table = 'role'
role_permission_table = "role_permission"
permission_table = "permission"
volume_iops_table = 'volume_iops'
policy_table = 'access_policy'
qos_table = 'QOS'
snapshot_table = 'snapshot'
cgsnapshot_table = 'snapshot_group'
rrserver_table = "rrserver"
rrclient_table = "rrclient"
vgroup_table = 'vgroup'
snapshot_policy_table = "snapshot_policy"
protection_domain_table = 'protection_domain'
sysconfig_table = 'sysconfig'
sysconfig_for_ump_table = 'sysconfig_for_ump'
volume_latency_table = 'volume_latency'
latency_table = 'latency'
task_table = 'task'
schedule_job_table = 'schedule_job'
schedule_job_report_table = 'schedule_job_report'
mail_table = 'mail'
customer_table = 'customer'
folder_table = 'folder'
license_table = 'license'

filter_table = [pool_table, volume_table, qos_table, vgroup_table, snapshot_table, cgsnapshot_table, folder_table]


class Struct(object):
    """Comment removed"""
    def __init__(self, data):
        for name, value in data.iteritems():
            setattr(self, name, self._wrap(value))
            
    def _wrap(self, value):
        if isinstance(value, (tuple, list, set, frozenset)):
            return type(value)([self._wrap(v) for v in value])
        else:
            return value if isinstance(value, dict) else value
    

def dict2object(data):
    if isinstance(data, dict):
        data = Struct(data)
        return data
    
    result = []
    if isinstance(data, (tuple, list, set, frozenset)):
        for x in data:
            o = Struct(x)
            result.append(o)
    return  result


def parse_return(redata, is_count=False, is_obj=True):
    redata = json.loads(redata)
    if redata.get('reply', {}).get('is_success'):
        obj = redata.get('records')
        if is_count:
            return obj
        if not is_obj :
            return obj
        if obj:
            return dict2object(obj)
        return obj
    else:
        error = redata.get('reply', {}).get('error', '')
        if "No row was found" in error or "操作对象已不存在，请重新操作" in error:
            raise NoResultFound(error)
        raise Exception(error)


def db_query_obj(body, url="/api/v1/db", is_obj=True):
    redata = web.config._server.api_sync_call(body, url=url)
    return parse_return(redata, is_obj=is_obj)


def db_query(params):
    if params.get('table') in filter_table:
        user_id = web.config._session.user.id
        username = web.config._session.user.name
        if not check_is_adminstrator(username):
            params.get('filter_by', {})['user_id'] = user_id
    body = {"QueryDB":{'params':params}}
    is_obj = params.get('is_obj', True)
    return db_query_obj(body, is_obj=is_obj)


def db_count(params):
    body = {"QueryDB":{'params':params}}
    redata = web.config._server.api_sync_call(body, url="/api/v1/db")
    return parse_return(redata, is_count=True)


def get_list(table, spec={}):
    params = {'table':table,'filter_by':spec,'mode':'all'}
    return db_query(params)


def oplog_create(values):
    body = {"EventCreate": {'params':values}}
    redata = web.config._server.api_sync_call(body)
    return parse_return(redata)


def rewrite_ResourceClosedError(func):
    def new_func(*args,**kwargs):
        try:
            return func(*args, **kwargs)
        except ResourceClosedError, e:
            if str(e).find('Cannot end transaction context') != -1:
                raise ResourceClosedError('创建失败，已存在相同记录')

    return new_func

def cluster_get_all(session=None):
    params = {'table':cluster_table,'mode':'all'}
    return db_query(params)

def cluster_get(p_id, read_deleted='no', session=None):
    params = {'table':cluster_table,'mode':'first'}
    return db_query(params)

def cluster_get_with_iqn(iqn, read_deleted='no', session=None):
    params = {'table':cluster_table,'filter_by':{'iqn':iqn},'mode':'all'}
    return db_query(params)

def cluster_get_with_parent_id(parent_id, 
        read_deleted='no', session=None):
    params = {'table':cluster_table,'filter_by':{'parent_id':parent_id},'mode':'all'}
    return db_query(params)

def cluster_get_with_type(p_type, session=None):
    clusters = model_query(Cluster, read_deleted='no', session=session) \
            .filter_by(type=p_type).filter_by(parent_id=parent_id).all()
    return clusters

def cluster_get_with_parent_name(parent_id, name, session=None):
    body['params'] = {'table':cluster_table,'filter_by':{'parent_id':parent_id,'name':name},'mode':'all'}
    return db_query(params)

def cluster_get_with_cluster_name(clustername, session=None):
    body['params'] = {'table':cluster_table,'filter_by':{'cluster_name':clustername},'mode':'all'}
    return db_query(params)

def cluster_count_with_ccid(ccid):
    return model_query(Cluster, read_deleted='no')\
            .filter_by(ccid=ccid).count()

def disk_get_device(host_id,device,session=None):
    params = {'table':disk_table,'filter_by':{'host_id':host_id,'device':device},'mode':'one'}
    return db_query(params)

def disk_get_all_device(host_id,device,session=None):
    params = {'table':disk_table,'filter_by':{'host_id':host_id,'device':device},'mode':'all'}
    return db_query(params)

def disk_get_serial_number_all(host_id,serial_number,session=None):
    params = {'table':disk_table,'filter_by':{'host_id':host_id,'serial_number':serial_number},'mode':'all'}
    return db_query(params)

def disk_get_isjoin_device(host_id, isjoin,session=None):
    params = {'table':disk_table,'filter_by':{'host_id':host_id,'isjoin':isjoin},'mode':'all'}
    return db_query(params)

def disk_get(id,session=None):
    params = {'table':disk_table,'filter_by':{'id':id},'mode':'one'}
    return db_query(params)

def disk_get_with_host(host_id):
    params = {'table':disk_table,'filter_by':{'host_id':host_id},'mode':'all'}
    return db_query(params)

def disk_get_with_host_stat(host_id,stat):
    params = {'table':disk_table,'filter_by':{'host_id':host_id,'stat':stat},'mode':'all'}
    return db_query(params)

def disk_get_with_isjoin(isjoin):
    params = {'table':disk_table,'filter_by':{'isjoin':isjoin},'mode':'all'}
    return db_query(params)

@rewrite_ResourceClosedError
def cluster_create(values):
    '''当前cluster_的ccid是用文件锁来保证唯一的'''
    type = values.get('type')
    session = get_session()
    with session.begin(subtransactions=True):
        cluster = Cluster()
        cluster.update(values)
        cluster.save(session=session)
        return cluster

def cluster_update(p_id, values):
    session = get_session()
    with session.begin(subtransactions=True):
        cluster = cluster_get(p_id, session=session)
        cluster.update(values)
        cluster.save(session=session)
        return cluster

def host_get(host_id, session=None):
    params = {'table':host_table,'filter_by':{'id':host_id},'mode':'one'}
    return db_query(params)

def host_get_all(session=None):
    """Get all hosts."""
    params = {'table':host_table,'mode':'all'}
    return db_query(params)

def host_get_with_cluster(cluster_id):
    """Get all hosts with cluster."""
    params = {'table':host_table,'filter_by':{'cluster_id':cluster_id},'mode':'all'}
    return db_query(params)

def host_get_with_name(name):
    params = {'table':host_table,'filter_by':{'name':name},'mode':'all'}
    return db_query(params)

def pool_get_all():
    params = {'table': pool_table, 'mode':'all'}
    return db_query(params)

def pool_get(id):
    params = {'table': pool_table, 'filter_by':{'id': id}, 'mode': 'one'}
    return db_query(params)

def folder_get(id):
    params = {'table': folder_table, 'filter_by':{'id': id}, 'mode': 'one'}
    return db_query(params)

def folder_get_all(session=None):
    params = {'table':folder_table,'mode':'all'}
    return db_query(params)


def pool_get_with_user(user_id):
    params = {'table': pool_table, 'filter_by':{'user_id': user_id}, 'mode':'all'}
    return db_query(params)


def user_create(values):
    name = values.get('name')
    if model_query(User, read_deleted='no')\
            .filter_by(name=name).count() >= 1:
        raise Duplica('指定的用户名已被使用')

    session = get_session()
    with session.begin(subtransactions=True):
        user = User()
        user.update(values)
        user.save(session=session)
        return user

def user_get_with_name(name):
    params = {'table':user_table,'filter_by':{'name':name},'mode':'first'}
    return db_query(params)

def user_get_all():
    params = {'table':user_table,'mode':'all'}
    return db_query(params)

def user_get(userid):
    params = {'table':user_table,'filter_by':{'id':userid },'mode':'first'}
    return db_query(params)

def role_get(id):
    params = {'table':role_table,'filter_by':{'id':id},'mode':'first'}
    return db_query(params)

def user_role_get_with_userid(user_id):
    params = {'table':user_role_table,'filter_by':{'user_id':user_id},'mode':'all'}
    return db_query(params)

def role_permission_get_with_roleid(role_id):
    params = {'table':role_table,'filter_by':{'id':role_id},'mode':'first', 'relationships':'permissions'}
    return db_query(params)

def permission_get(p_id):
    params = {'table':permission_table,'filter_by':{'id':p_id},'mode':'one'}
    return db_query(params)

def volume_get_all(session=None):
    params = {'table':volume_table,'filter_by':{'fake_deleted':False},'mode':'all'}
    return db_query(params)

def volume_get(volume_id, session=None):
    params = {'table':volume_table,'filter_by':{'id':volume_id},'mode':'first'}
    return db_query(params)

def volume_get_with_poolid(pool_id):
    params = {'table':volume_table, 'filter_by':{'pool_id':pool_id},'mode':'all'}
    return db_query(params)

def volume_get_with_user(user_id):
    params = {'table':volume_table, 'filter_by':{'user_id':user_id},'mode':'all'}
    return db_query(params)

def volume_get_with_qos(qos_id):
    params = {'table':volume_table,'filter_by':{'qos_id':qos_id},'mode':'all'}
    return db_query(params)


def volume_get_with_policy(access_policy_id):
    params = {'table':volume_table,'filter_by':{'access_policy_id':access_policy_id},'mode':'all'}
    return db_query(params)


def volume_get_with_vgroup(vgroup_id):
    params = {'table':volume_table,'filter_by':{'vgroup_id':vgroup_id},'mode':'all'}
    return db_query(params)

def folder_get_all(session=None):
    params = {'table':folder_table,'mode':'all'}
    return db_query(params)


def iops_get_with_cluster_status_all(cluster_id, status,):
    params = {'table':iops_table,'filter_by':{'cluster_id':cluster_id,'status':status},'mode':'all'}
    return db_query(params)


def iops_get_with_cluster_status(cluster_id, status):
    params = {'table':iops_table,'filter_by':{'cluster_id':cluster_id,'status':status},'mode':'first'}
    return db_query(params)


def latency_get_with_cluster(cluster_id):
    params = {'table':latency_table, 'filter_by':{'cluster_id':cluster_id},'mode':'first'}
    return db_query(params)

def volume_iops_get(iops_id):
    params = {'table':volume_iops_table, 'filter_by':{'id':iops_id}, 'mode':'first'}
    return db_query(params)

def volume_iops_get_with_volume(volume_id):
    params = {'table':volume_iops_table, 'filter_by':{'volume_id':volume_id}, 'mode':'last'}
    return db_query(params)

def access_control_get(pid):
    params = {'table':policy_table,'filter_by':{'id':pid},'mode':'one'}
    return db_query(params)

def access_control_get_all():
    params = {'table':policy_table, 'mode':'all'}
    return db_query(params)

def qos_get(pid):
    params = {'table':qos_table, 'filter_by':{'id':pid},'mode':'one'}
    return db_query(params)

def qos_get_all():
    params = {'table':qos_table, 'mode':'all'}
    return db_query(params)

def snapshot_get_with_volume(volume_id):
    params = {'table':snapshot_table,'filter_by':{'volume_id':volume_id}, 'mode':'all'}
    return db_query(params)

def snapshot_get(snapshot_id):
    params = {'table':snapshot_table,'filter_by':{'id':snapshot_id}, 'mode':'first'}
    return db_query(params)

def cgsnapshot_get(cgsnapshot_id):
    params = {'table':cgsnapshot_table,'filter_by':{'id':cgsnapshot_id}, 'mode':'one'}
    return db_query(params)

def vgroup_get(vgroup_id):
    params = {'table':vgroup_table,'filter_by':{'id':vgroup_id}, 'mode':'first'}
    return db_query(params)


def snappolicy_get_all():
    params = {'table':snapshot_policy_table, 'mode':'all'}
    return db_query(params)


def alert_get_all():
    params = {'table':alert_table, 'mode':'all'}
    return db_query(params)

def alert_count_nothandled():
    params = {'table':alert_table, 'mode':'count', 'filter_by':{'is_handled':False}}
    return db_count(params)

def alert_count_all():
    params = {'table':alert_table, 'mode':'count', 'filter_by':{'is_handled':False}}
    return db_count(params)

def alert_count_error():
    params = {'table':alert_table, 'mode':'count', 'filter_by':{'level':'ERROR', 'is_handled':False}}
    return db_count(params)

def alert_count_warn():
    params = {'table':alert_table, 'mode':'count', 'filter_by':{'level':'WARNING','is_handled':False}}
    return db_count(params)

def protection_domain_get(pid):
    params = {'table':protection_domain_table, 'filter_by':{'id':pid},'mode':'one'}
    return db_query(params)

def protection_domain_get_all():
    params = {'table':protection_domain_table, 'mode':'all'}
    return db_query(params)

def protection_domain_get_with_user(user_id, session=None):
    params = {'table':user_table, 'filter_by':{'id':user_id},'mode':'one', 'relationships':'protection_domains'}
    return db_query(params)

def protection_domain_get_with_pool(pool_id, session=None):
    params = {'table':pool_table, 'filter_by':{'id':pool_id},'mode':'one', 'relationships':'protection_domains'}
    return db_query(params)

def role_get_with_user(user_id, session=None):
    params = {'table':user_table, 'filter_by':{'id':user_id},'mode':'one', 'relationships':'roles'}
    return db_query(params)

def snappolicy_get_with_volume(volume_id, session=None):
    params = {'table':volume_table, 'filter_by':{'id':volume_id},'mode':'one', 'relationships':'snapshot_policys'}
    return db_query(params)

def sysconfig_get(config_id, session=None):
    params = {'table':sysconfig_table, 'filter_by':{'id':config_id},'mode':'first'}
    return db_query(params)

def sysconfig_for_ump_get(config_id, session=None):
    params = {'table':sysconfig_for_ump_table, 'filter_by':{'id':config_id},'mode':'first'}
    return db_query(params)

def rrserver_get_with_rrclient(cid):
    params = {'table':rrclient_table, 'filter_by':{'id':cid},'mode':'one', 'relationships':'rrservers'}
    return db_query(params)


def rrserver_get(rid):
    params = {'table':rrserver_table, 'filter_by':{'id':rid}, 'mode':'first'}
    return db_query(params)

def rrclient_get(rid):
    params = {'table':rrclient_table, 'filter_by':{'id':rid}, 'mode':'first'}
    return db_query(params)


def rrserver_get_all():
    params = {'table':rrserver_table, 'mode':'all'}
    return db_query(params)


def volume_latency_get(volume_id):
    params = {'table':volume_latency_table, 'filter_by':{'volume_id':volume_id}, 'mode':'all'}
    return db_query(params)


def health_get_with_cluster(cid):
    params = {'table':cluster_table, 'filter_by':{'id':cid},'mode':'one', 'relationships':'health'}
    return db_query(params)


def schedule_job_get_with_classname(name):

    params = {'table': schedule_job_table, 'filter_by': {'class_name': name}, 'mode': 'first'}
    return db_query(params)


def schedule_job_get_with_config(cid):

    params = {'table': schedule_job_table, 'filter_by': {'sysconfig_for_ump_id': cid}, 'mode': 'first'}
    return db_query(params)


def schedule_job_report_get(report_id):
    params = {'table':schedule_job_report_table, 'filter_by':{'id':report_id},'mode':'first'}
    return db_query(params)


def task_get_with_status(status):
    params = {'table': task_table, 'filter_by':{'status':status, 'is_show':True}, 'mode':'all', 'is_obj':False}
    return db_query(params)


def task_get(task_id):
    params = {'table': task_table, 'filter_by':{'id':task_id}, 'mode':'one'}
    return db_query(params)


def task_get_recent(limit=10):
    params = {'table': task_table, 'filter_by':{'is_show':True}, 'order_by': 'created_at desc', 'not_equal':{'status':'processing'}, 'limit':limit,  'mode':'all', 'is_obj':False}
    return db_query(params)


def mail_get_first():
    params = {'table': mail_table, 'mode': 'first'}
    return db_query(params)


def customer_get_first():
    params = {'table':customer_table, 'mode': 'first'}
    return db_query(params)


def user_attrget_role(username):
    user = user_get_with_name(username)
    if not user:
        return False
    roles = role_get_with_user(user.id)
    if not roles:
        return False

    role_id = roles[0].id
    role = role_get(role_id)
    return role


def check_is_adminstrator(username):
    role = user_attrget_role(username)
    if role and role.name == 'administrator':
        return True
    return False


def check_permission(username, resource):
    user = user_get_with_name(username)
    if not user:
        return False
    role = user_attrget_role(username)
    if not role:
        return False

    if role.name == 'administrator':
        return True
    rolePermissons = role_permission_get_with_roleid(role.id)
    permissons = [permission_get(permisson.id) for permisson in rolePermissons] 
    permissons = [permisson.resource_type for permisson in permissons] 
    return resource in permissons

def license_capacity_get():
    params = {'table': license_table, 'filter_by': {'company': 'huayun'}, 'mode': 'all'}
    return db_query(params)

if __name__ == '__main__':
    pass
